package xyz.lwm.lazycat.test;

import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.model.InitializationError;
import xyz.lwm.lazycat.beans.Application;
import xyz.lwm.lazycat.beans.BeanDesignUtil;
import xyz.lwm.lazycat.beans.BeanRefFilter;
import xyz.lwm.lazycat.utility.CollectionUtil;
import xyz.lwm.lazycat.utility.It;
import xyz.lwm.lazycat.utility.StringUtil;
import xyz.lwm.lazycat.utility.reflect.AnnotationUtil;
import xyz.lwm.lazycat.utility.reflect.Annotations;
import xyz.lwm.lazycat.utility.reflect.ReflectUtil;

import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 结合 {@link xyz.lwm.lazycat.setting.Setting} 使用, 可以选择 profile
 * <pre>{@code
 *
 * @RunWith(LazycatRunner.class)
 * @LazycatTest(profile="dev")
 * @BeanScan("com.test.**")
 * public class Test {
 *     @Test
 *     public void test() {
 *         System.out.println("hello");
 *     }
 * }
 *
 * }</pre>
 */
public class LazycatRunner extends BlockJUnit4ClassRunner {

    private static final String PORT = "setting.port";

    private static final String PROFILE = "setting.profiles";

    private static final String JAVA_COMMAND  = "sun.java.command";

    private final Application app = new Application();

    public LazycatRunner(Class<?> testClass) throws InitializationError {
        super(testClass);
        init(testClass);
    }

    private void init(Class<?> testClass) {
        Annotations annotations = AnnotationUtil.getAnnotations(testClass);
        It<LazycatTest> it = It.of(annotations.getAnnotation(LazycatTest.class));

        if (it.isPresent()) {
            // 设置端口
            it.let(LazycatTest::port).filter(p -> p > 0)
                    .also(p -> System.setProperty(PORT, String.valueOf(p)));
            // 设置 profile
            it.let(LazycatTest::profile).filter(StringUtil::isNotBlank)
                    .also(profile -> System.setProperty(PROFILE, profile));
            // 设置启动类
            It<? extends Class<?>> classIt = it.let(LazycatTest::baseClass).filter(clz -> clz != void.class);
            Class<?> startupClass = classIt.isPresent() ? classIt.get() : testClass;
            System.setProperty(JAVA_COMMAND, startupClass.getName());

            // 获取 bean 类
            Set<Class<?>> beanClasses = it.let(LazycatTest::beanClasses).let(Arrays::stream)
                    .let(stream -> stream.collect(Collectors.toSet()))
                    .also(classes -> classes.add(testClass)).getOr(Collections.emptySet());

            // 注册 bean design
            app.addRegistry(beanRegistry -> {
                for (Class<?> clz : beanClasses) {
                    BeanDesignUtil.buildDesign(clz).also(beanRegistry::register);
                }
            });

            // 添加 bean ref 过滤器
            it.let(LazycatTest::beanRefFilter).filter(CollectionUtil::isNotEmpty).also(filters -> {
                for (Class<? extends BeanRefFilter> clz : filters) {
                    app.addBeanRefFilter(ReflectUtil.newInstance(clz));
                }
            });
        }

        app.start();
    }

    @Override
    protected Object createTest() throws Exception {
        return app.getBeans().get(getTestClass().getJavaClass());
    }

}
